(ns com.ufo5260987423.graphDatabase.client.clojure.core
  (:use com.ufo5260987423.graphDatabase.client.clojure.utils)
  (:use com.ufo5260987423.graphDatabase.client.clojure.gao)
  (:import (java.net Socket)
           (java.io PrintWriter InputStreamReader BufferedReader)))

(def history-map (ref {}))
(declare conn-handler)
(declare conn)

(defn connect [server]
  (let [socket (Socket. (:name server) (:port server))
        in (BufferedReader. (InputStreamReader. (.getInputStream socket)))
        out (PrintWriter. (.getOutputStream socket))
        conn (ref {:in in :out out})]
    (doto (Thread. #(conn-handler conn)) (.start))
    conn))

(defn close-database []
  (.close (:in @conn))
  (.close (:out @conn))
  (def conn nil))

(defn handle-history-promise [target]
  (loop [flag (promise? (get @history-map (first (first target))))]
    (if flag
      (if (not (empty? target))
        (dosync (deliver (get @history-map (first (first target))) (last (first target)))))
      (recur (promise? (get @history-map (first (first target))))))))

(defn write [conn msg]
  (dosync
    (let [id (count @history-map)
          sendMsg {id msg}]
      (ref-set history-map (conj @history-map {id (promise)}))
      (doto (:out @conn)
        (.println (str sendMsg "\r"))
        (.flush))
      id)))

(defn conn-handler [conn]
  (while (nil? (:exit @conn))
    (let [msg (.readLine (:in @conn))]
      (if (not (nil? msg))
        (handle-history-promise (eval-string msg))
        msg))))

(defn write-with-reply [msg]
  (println msg)
  (if (nil? msg)
    nil
    (loop [x (write conn msg)]
      (if (realized? (@history-map x))
        @(@history-map x)
        (recur x)))))

(defn search-graph-node-by [attribute-name attribute-value]
  (write-with-reply
    (list 'search-graph-node-by attribute-name attribute-value)))

(defn create-connect [ip port]
  (connect (server ip port)))

(defn use-database [ip port]
  (if (nil? conn)
    nil
    (def conn (create-connect ip port))))

(defn get-node [id]
  (write-with-reply (list 'get-node id)))

(defn save-node [graph-node]
  (Integer. (write-with-reply (list 'save-node graph-node))))

(defn delete-node [graph-node-id]
  (write-with-reply (list 'delete-node graph-node-id)))

(defn save-edge [graph-edge]
  (write-with-reply (list 'save-edge graph-edge)))